<?php


/**
 * author : Marc Quinton / April 2008.
 *
 *  a simple task management framework using pcntl_fork, pcntl_wait.
 *
 *  - see at bottom for a sample usage.
 *  - you shoud overring Task class (SleepingClass is an example), and manage them in a pool, using taskManager
 */
/*
error_reporting(E_ALL);

class Task {

    protected $pid;
    protected $ppid;

    function __construct(){
    }

    function fork(){
        $pid = pcntl_fork();
        if ($pid == -1)
            throw new Exception ('fork error on Task object');
        elseif ($pid) {
            # we are in parent class
            $this->pid = $pid;
            # echo "< in parent with pid {$his->pid}\n";
        } else{
            # we are is child
            $this->run();
        }
    }

    function run(){
        # echo "> in child {$this->pid}\n";
        # sleep(rand(1,3));
        $this->ppid = posix_getppid();
        $this->pid = posix_getpid();
    }

    # call when a task in finished (in parent)
    function finish(){
        echo "task finished {$this->pid}\n";
    }

    function pid(){
        return $this->pid;
    }
}

class SleepingTask extends Task{
    function run(){
        parent::run();
        echo "> in child {$this->pid}\n";

        # print_r($this);

        sleep(rand(1,5));
        echo "> child done {$this->pid}\n";
        exit(0);
    }
}

class TaskManager{

    protected $pool;

    function __construct(){
        $this->pool = array();
    }

    function add_task($task){
        $this->pool[] = $task;
    }

    function run(){

        foreach($this->pool as $task){
            $task->fork();
        }

        # print_r($this);
        # sleep(60);

        while(1){
            echo "waiting\n";
            $pid = pcntl_wait($extra);
            if($pid == -1)
                break;

            echo ": task done : $pid\n";
            $this->finish_task($pid);
        }

        echo "processes done ; exiting\n";
        exit(0);
    }

    function finish_task($pid){
        $task = $this->pid_to_task($pid);
        if($task){
            $task->finish();
        }
    }

    function pid_to_task($pid){
        foreach($this->pool as $task){
            if($task->pid() == $pid)
                return $task;
        }
        return false;
    }
}

$manager = new TaskManager();

for($i=0 ; $i<10 ; $i++)
    $manager->add_task(new SleepingTask());

$manager->run();



/*

$children = 5; # likely a function call here.

for ($i=1; $i<=$children; $i++) {
    $pid = pcntl_fork();
    if ($pid == -1) {
        die("could not fork\n");
    } else if ($pid) {
	    # If we are the parent, we did our job of giving birth,
	    # now lets finish our job and die!
        exit(0);
    } else {
	    # Since we are the child, fork so that init will become our parent.  Init
	    # is good at wait()ing on children - ie: reaping.
	    $cpid = pcntl_fork();
	    if ($cpid == -1) {
            die("could not fork in child process\n");
        }
	    if (!$cpid) {
		      # We have now forked off from our parent and also are not waiting on any
		      # other children to process, however other children are running
		      # simutaniously to us.  Make sure the code you write here is safe to run
		      # in this environment of multiprocessing - ie: proper locking, etc.
		      # Write the custom code here that you want to multiprocess.
		
		      # ADD CODE HERE TO MULTIPROCESS
		      print "we are child ($cpid) number $i\n";
		      
		      sleep(2);
		      
		      print " * exit child number $i\n";
		      # Don't forget to exit after the child processing is done.  Certainly
		      # change this exit code if you need to however.
		      exit(0);
        }
    }
}

echo "Exit parent!!!\n";
*/

/*
// Include PEAR's Daemon Class
require_once "System/Daemon.php";

// Bare minimum setup
System_Daemon::setOption("appName", "mydaemonname");

// Spawn Deamon!
System_Daemon::start();

// Your PHP Here!
while (true) {
    
    System_Daemon::defaultSigHandler();
    
    echo "I'm live!!!\n";
    sleep(2);
    
}

// Stop daemon!
System_Daemon::stop();
*/


/*declare(ticks=1);

echo "Tut\n";

$pid = pcntl_fork();
if ($pid == -1) {
     die("could not fork"); 
} else if ($pid) {
     exit(); // we are the parent 
} else {
     // we are the child
}

echo "Tut1\n";

// detatch from the controlling terminal
if (posix_setsid() == -1) {
    die("could not detach from terminal");
}

echo "Tut2\n";

// setup signal handlers
pcntl_signal(SIGTERM, "sig_handler");
pcntl_signal(SIGHUP, "sig_handler");

// loop forever performing tasks
while (1) {

    echo "I'm live! ($pid)\n";
    sleep(1);
    // do something interesting here
}


echo "Tut3\n";

function sig_handler($signo) 
{

     switch ($signo) {
         case SIGTERM:
             // handle shutdown tasks
             echo "I'm killed.... =((((\n";
             exit;
             break;
         case SIGHUP:
             // handle restart tasks
             echo "Yahooo! SIGHUP\n";
             break;
         default:
             // handle all other signals
             echo "Yahooo!\n";
     }

} */

?>
